package org.iabako.server.serviceimpl.business;

import org.iabako.server.dao.JpaDAO;
import org.iabako.server.dao.business.PaymentDAO;
import org.iabako.server.dao.business.QueryDefinitionDAO;
import org.iabako.server.tools.ServerTools;
import org.iabako.shared.entity.business.AbstractEntity;
import org.iabako.shared.entity.business.Payment;
import org.iabako.shared.entity.business.Sale;
import org.iabako.shared.entity.enumeration.TrackingType;
import org.iabako.shared.exception.IabakoPackageForbiddenException;
import org.iabako.shared.iservice.business.PaymentService;
import org.iabako.shared.iservice.business.SaleService;
import org.iabako.shared.iservice.business.TrackingService;
import org.iabako.shared.iservice.user.UserService;
import org.iabako.shared.querydefinition.SearchMotorQueryEnum;
import org.iabako.shared.querydefinition.dto.QueryDefinitionDTO;
import org.iabako.shared.tools.GenericTools;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * Created by jose on 28/08/14.
 */

@org.springframework.stereotype.Service("paymentService")
public class PaymentServiceImpl extends AbstractServiceImpl implements PaymentService {

    @Autowired
    private PaymentDAO paymentDAO;
    @Autowired
    private SaleService saleService;
    @Autowired
    private UserService userService;
    @Autowired
    private QueryDefinitionDAO queryDefinitionDAO;
    @Autowired
    private TrackingService trackingService;

    @Override
    protected JpaDAO getDAO() {
        return paymentDAO;
    }

    public QueryDefinitionDTO getSearchQueryDefinitionDTO(QueryDefinitionDTO qd) {
        qd.setSearchMotorQuery(SearchMotorQueryEnum.PaymentSearch);
        queryDefinitionDAO.executeQueryDefinition(qd);
        return qd;
    }

    public QueryDefinitionDTO setSearchCriteriaFromSuggest(QueryDefinitionDTO qd, Long hiddenSelectionCode, String value) {
        return null;
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Payment save(Payment payment, boolean noTrack) throws IabakoPackageForbiddenException {
        payment.setScheduleDate(GenericTools.getDateFromString(payment.getScheduleDateString()));
        payment.setDate(GenericTools.getDateFromString(payment.getDateString()));

        boolean isCreation = payment.getId() == null;

        Sale sale = (Sale) saleService.getById(payment.getSale().getId());

        if (isCreation) {
            sale.getPayments().add(payment);
            userService.addInvoiceReceiptToEnterpriseBalance(null, payment);
        }
        if (!noTrack) {
            trackingService.addTrackingToUserSession(isCreation ? TrackingType.paymentReceivedNew : TrackingType.paymentReceivedModify, sale);
        }

        payment.setAmount(ServerTools.round(payment.getAmount()));
        //Persist or merge payment (Id will be used in async call return)
        payment = (Payment) super.save(payment);

        sale.setRecalculatedTotal(sale.calculateAmountFromPaymentsAndInstalments());
        saleService.rawSave(sale);

        return payment;
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Payment save(Payment payment) throws IabakoPackageForbiddenException {
        return save(payment, false);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Boolean remove(Payment payment, boolean noTrack) {
        Sale sale = payment.getSale();
        sale.getPayments().remove(payment);

        sale.setRecalculatedTotal(sale.calculateAmountFromPaymentsAndInstalments());
        setBusinessTrackInfo(sale);

        saleService.calculateStatusAndSave(sale, false);

        if (!noTrack) {
            trackingService.addTrackingToUserSession(TrackingType.paymentReceivedDelete, sale);
        }

        return super.remove(payment);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Boolean remove(AbstractEntity abstractEntity) {
        return remove((Payment) abstractEntity, false);
    }

    public List<Payment> getBySale(Sale entity) {
        return paymentDAO.findBySale(entity);
    }
}
